package controller

import (
	config2 "go-pan/internal/config"
	"go-pan/internal/log"
	"go-pan/internal/model"
	utils2 "go-pan/internal/utils"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

type RegisterRequest struct {
	Username string `json:"username" binding:"required,min=3,max=64"`
	Password string `json:"password" binding:"required,min=6,max=64"`
	Email    string `json:"email" binding:"omitempty,email"`
}

type LoginRequest struct {
	Username string `json:"username" binding:"required"`
	Password string `json:"password" binding:"required"`
}

func Register(c *gin.Context) {
	var req RegisterRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		log.AuthLogger.Warn("registration request validation failed",
			zap.String("ip", c.ClientIP()),
			zap.Error(err))
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// 查询是否已有用户
	var existUser model.User
	if err := config2.DB.Where("username = ?", req.Username).First(&existUser).Error; err == nil {
		log.AuthLogger.Warn("registration failed: username already exists",
			zap.String("username", req.Username),
			zap.String("ip", c.ClientIP()))
		c.JSON(http.StatusBadRequest, gin.H{"error": "user exist"})
		return
	}

	// 如果提供了邮箱，检查邮箱是否已被使用
	if req.Email != "" {
		var existEmailUser model.User
		if err := config2.DB.Where("email = ?", req.Email).First(&existEmailUser).Error; err == nil {
			log.AuthLogger.Warn("registration failed: email already exists",
				zap.String("email", req.Email),
				zap.String("ip", c.ClientIP()))
			c.JSON(http.StatusBadRequest, gin.H{"error": "email already exists"})
			return
		}
	}

	// 密码加密
	hash, err := utils2.HashPassword(req.Password)
	if err != nil {
		log.SystemLogger.Error("password hashing failed during registration",
			zap.String("username", req.Username),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "password hash failed"})
		return
	}

	// 生成分布式ID
	userID := utils2.GenDistributeId()

	// 处理邮箱：空字符串转为 nil（NULL）
	var emailPtr *string
	if req.Email != "" {
		emailPtr = &req.Email
	}

	user := model.User{
		ID:           userID,
		Username:     req.Username,
		PasswordHash: hash,
		Email:        emailPtr,
	}

	if err := config2.DB.Create(&user).Error; err != nil {
		log.SystemLogger.Error("user creation failed",
			zap.String("username", req.Username),
			zap.Int64("user_id", userID),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "register fail"})
		return
	}

	// 生成 access token
	accessToken, err := utils2.GenerateToken(user.ID, user.Username)
	if err != nil {
		log.SystemLogger.Error("token generation failed during registration",
			zap.Int64("user_id", user.ID),
			zap.String("username", user.Username),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "generate token fail"})
		return
	}

	// 生成 refresh token
	refreshToken, err := utils2.GenerateRefreshToken(user.ID, user.Username)
	if err != nil {
		log.SystemLogger.Error("refresh token generation failed during registration",
			zap.Int64("user_id", user.ID),
			zap.String("username", user.Username),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "generate refresh token fail"})
		return
	}

	// 生成 CSRF token
	csrfToken, err := utils2.GenerateCSRFToken(user.ID)
	if err != nil {
		log.SystemLogger.Error("CSRF token generation failed during registration",
			zap.Int64("user_id", user.ID),
			zap.String("username", user.Username),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "generate csrf token fail"})
		return
	}

	cfg := config2.GetConfig()
	accessExpiration := time.Duration(cfg.JWT.Expiration) * time.Hour
	refreshExpiration := time.Duration(cfg.JWT.RefreshExpiration) * time.Hour

	c.SetCookie("token", accessToken, int(accessExpiration.Seconds()), "/", "", false, true)
	c.SetCookie("refresh_token", refreshToken, int(refreshExpiration.Seconds()), "/", "", false, true)
	c.SetCookie("csrf_token", csrfToken, 24*3600, "/", "", false, false) // CSRF token 不需要 HttpOnly

	// 认证日志：用户注册成功
	log.AuthLogger.Info("user registered successfully",
		zap.Int64("user_id", user.ID),
		zap.String("username", user.Username),
		zap.String("ip", c.ClientIP()),
		zap.String("email", req.Email))

	// 审计日志：用户注册
	log.AuditLogger.Info("user registration",
		zap.Int64("user_id", user.ID),
		zap.String("username", user.Username),
		zap.String("ip", c.ClientIP()),
		zap.Time("timestamp", time.Now()))

	c.JSON(http.StatusOK, gin.H{
		"message":      "注册成功",
		"access_token": accessToken,
		"csrf_token":   csrfToken,
	})
}

func Login(c *gin.Context) {
	var req LoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		log.AuthLogger.Warn("login request validation failed",
			zap.String("ip", c.ClientIP()),
			zap.Error(err))
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	var user model.User
	if err := config2.DB.Where("username = ?", req.Username).First(&user).Error; err != nil {
		log.AuthLogger.Warn("login failed: user not found",
			zap.String("username", req.Username),
			zap.String("ip", c.ClientIP()))
		c.JSON(http.StatusUnauthorized, gin.H{"error": "username or password wrong"})
		return
	}

	if !utils2.CheckPasswordHash(req.Password, user.PasswordHash) {
		log.AuthLogger.Warn("login failed: invalid password",
			zap.Int64("user_id", user.ID),
			zap.String("username", req.Username),
			zap.String("ip", c.ClientIP()))
		c.JSON(http.StatusUnauthorized, gin.H{"error": "username or password wrong"})
		return
	}

	// 生成 access token
	accessToken, err := utils2.GenerateToken(user.ID, user.Username)
	if err != nil {
		log.SystemLogger.Error("token generation failed during login",
			zap.Int64("user_id", user.ID),
			zap.String("username", user.Username),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "generate token fail"})
		return
	}

	// 生成 refresh token
	refreshToken, err := utils2.GenerateRefreshToken(user.ID, user.Username)
	if err != nil {
		log.SystemLogger.Error("refresh token generation failed during login",
			zap.Int64("user_id", user.ID),
			zap.String("username", user.Username),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "generate refresh token fail"})
		return
	}

	// 生成 CSRF token
	csrfToken, err := utils2.GenerateCSRFToken(user.ID)
	if err != nil {
		log.SystemLogger.Error("CSRF token generation failed during login",
			zap.Int64("user_id", user.ID),
			zap.String("username", user.Username),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "generate csrf token fail"})
		return
	}

	cfg := config2.GetConfig()
	accessExpiration := time.Duration(cfg.JWT.Expiration) * time.Hour
	refreshExpiration := time.Duration(cfg.JWT.RefreshExpiration) * time.Hour

	c.SetCookie("token", accessToken, int(accessExpiration.Seconds()), "/", "", false, true)
	c.SetCookie("refresh_token", refreshToken, int(refreshExpiration.Seconds()), "/", "", false, true)
	c.SetCookie("csrf_token", csrfToken, 24*3600, "/", "", false, false) // CSRF token 不需要 HttpOnly

	// 认证日志：用户登录成功
	log.AuthLogger.Info("user logged in successfully",
		zap.Int64("user_id", user.ID),
		zap.String("username", user.Username),
		zap.String("ip", c.ClientIP()),
		zap.String("user_agent", c.Request.UserAgent()))

	// 审计日志：用户登录
	log.AuditLogger.Info("user login",
		zap.Int64("user_id", user.ID),
		zap.String("username", user.Username),
		zap.String("ip", c.ClientIP()),
		zap.Time("timestamp", time.Now()))

	c.JSON(http.StatusOK, gin.H{
		"message":      "login success",
		"access_token": accessToken,
		"csrf_token":   csrfToken,
	})
}

func Logout(c *gin.Context) {
	userInfo, ok := utils2.GetUserInfo(c)

	// 获取 access token 和 refresh token
	accessToken, _ := c.Cookie("token")
	refreshToken, _ := c.Cookie("refresh_token")

	// 将 token 加入黑名单
	if accessToken != "" {
		cfg := config2.GetConfig()
		accessExpiration := time.Duration(cfg.JWT.Expiration) * time.Hour
		if err := utils2.AddTokenToBlacklist(accessToken, accessExpiration); err != nil {
			log.SystemLogger.Warn("failed to add access token to blacklist",
				zap.Error(err))
		}
	}

	if refreshToken != "" {
		if err := utils2.RevokeRefreshToken(refreshToken); err != nil {
			log.SystemLogger.Warn("failed to revoke refresh token",
				zap.Error(err))
		}
	}

	// 清除Cookie
	c.SetCookie("token", "", -1, "/", "", false, true)
	c.SetCookie("refresh_token", "", -1, "/", "", false, true)
	c.SetCookie("csrf_token", "", -1, "/", "", false, false)

	if ok && userInfo != nil && !userInfo.IsGuest {
		// 审计日志：用户登出
		log.AuditLogger.Info("user logout",
			zap.Int64("user_id", userInfo.ID),
			zap.String("username", userInfo.Username),
			zap.String("ip", c.ClientIP()),
			zap.Time("timestamp", time.Now()))

		log.AuthLogger.Info("user logged out",
			zap.Int64("user_id", userInfo.ID),
			zap.String("username", userInfo.Username),
			zap.String("ip", c.ClientIP()))
	}

	c.JSON(http.StatusOK, gin.H{
		"message": "logout success",
	})
}

// RefreshToken 刷新 access token
func RefreshToken(c *gin.Context) {
	// 从 Cookie 获取 refresh token
	refreshToken, err := c.Cookie("refresh_token")
	if err != nil || refreshToken == "" {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "refresh token required"})
		return
	}

	// 验证 refresh token
	userID, username, err := utils2.ValidateRefreshToken(refreshToken)
	if err != nil {
		log.AuthLogger.Warn("refresh token validation failed",
			zap.String("ip", c.ClientIP()),
			zap.Error(err))
		c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid refresh token"})
		return
	}

	// 检查 refresh token 是否在黑名单中
	blacklisted, err := utils2.IsTokenBlacklisted(refreshToken)
	if err != nil {
		log.SystemLogger.Warn("failed to check refresh token blacklist",
			zap.Error(err))
	}
	if blacklisted {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "refresh token has been revoked"})
		return
	}

	// 生成新的 access token
	accessToken, err := utils2.GenerateToken(userID, username)
	if err != nil {
		log.SystemLogger.Error("token generation failed during refresh",
			zap.Int64("user_id", userID),
			zap.String("username", username),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "generate token fail"})
		return
	}

	// 生成新的 CSRF token
	csrfToken, err := utils2.GenerateCSRFToken(userID)
	if err != nil {
		log.SystemLogger.Error("CSRF token generation failed during refresh",
			zap.Int64("user_id", userID),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "generate csrf token fail"})
		return
	}

	cfg := config2.GetConfig()
	accessExpiration := time.Duration(cfg.JWT.Expiration) * time.Hour

	c.SetCookie("token", accessToken, int(accessExpiration.Seconds()), "/", "", false, true)
	c.SetCookie("csrf_token", csrfToken, 24*3600, "/", "", false, false)

	log.AuthLogger.Info("token refreshed",
		zap.Int64("user_id", userID),
		zap.String("username", username),
		zap.String("ip", c.ClientIP()))

	c.JSON(http.StatusOK, gin.H{
		"message":      "token refreshed",
		"access_token": accessToken,
		"csrf_token":   csrfToken,
	})
}

// GetCSRFToken 获取 CSRF token（用于前端请求）
func GetCSRFToken(c *gin.Context) {
	userInfo, ok := utils2.GetUserInfo(c)
	if !ok || userInfo == nil || userInfo.IsGuest {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}

	csrfToken, err := utils2.GenerateCSRFToken(userInfo.ID)
	if err != nil {
		log.SystemLogger.Error("CSRF token generation failed",
			zap.Int64("user_id", userInfo.ID),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "generate csrf token fail"})
		return
	}

	c.SetCookie("csrf_token", csrfToken, 24*3600, "/", "", false, false)

	c.JSON(http.StatusOK, gin.H{
		"csrf_token": csrfToken,
	})
}

func GetUserInfo(c *gin.Context) {
	// 从中间件获取用户信息
	userInfo, ok := utils2.GetUserInfo(c)
	if !ok || userInfo == nil || userInfo.IsGuest {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"id":       userInfo.ID,
		"username": userInfo.Username,
	})
}
